<?php
// +----------------------------------------------------------------------
// | ZGUAN [ 致力于帮助更多的中小企业物联网转型 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2024 https://www.zguan.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ZGUAN 并不是自由软件，未经许可不能去掉ZGUAN 相关版权
// +----------------------------------------------------------------------
// | Author: ZGUAN Team <admin@zguan.cn>  0769-82282996  15899929162
// +----------------------------------------------------------------------
namespace app\common\repositories\energy;

use think\facade\Db;
use app\common\dao\energy\EnergyBillDao;
use app\common\repositories\BaseRepository;
use app\common\repositories\bill\BillCateRepository;
use app\common\repositories\room\RoomBasicRepository;
use app\common\repositories\bill\BillBasicRepository;
use app\common\repositories\bill\BillCatalogRepository;
use app\common\repositories\energy\EnergyMeterRepository;
use app\common\repositories\energy\EnergySharedRoomRepository;
use app\common\repositories\property\users\PropertyUsersLogRepository;

/**
 * Class EnergyBillRepository
 *
 * @mixin EnergyBillDao
 */
class EnergyBillRepository extends BaseRepository
{

    public function __construct(EnergyBillDao $dao)
    {
        $this->dao = $dao;
    }


    public function getPropertyList(array $where, $page, $limit, int $propertyId = null)
    {
        $query = $this->dao->search($where, $propertyId);
        $count = $query->count();
        $list = $query->page($page, $limit)
            ->with([
                'propertyInfo' => function ($query) {
                    $query->bind(['property_name' => 'name']);
                },
                'energyMeterInfo' => function ($query) {
                    $query->bind(['energy_no' => 'energy_no']);
                }
            ])
            ->append(['total_amount'])
            ->order('id', 'desc')
            ->select();
        /** @var EnergyMeterRepository $energyMeterRepository */
        $energyMeterRepository = app()->make(EnergyMeterRepository::class);
        $energyTypeData = $energyMeterRepository::ENERGY_TYPE;
        foreach ($list as $k => &$v) {
            $v['type_name'] = $energyTypeData[$v['energy_type']] ?? '';
        }
        return compact('count', 'list');
    }


    public function addInfo(int $propertyId, array $data, int $userId)
    {
        return Db::transaction(function () use ($data, $propertyId, $userId) {

            /** @var EnergyMeterRepository $energyMeterRepository */
            $energyMeterRepository = app()->make(EnergyMeterRepository::class);

            $meterInfo = $energyMeterRepository->get($data['energy_id']);

            /** @var EnergyPlanRepository $energyPlanRepository */
            $energyPlanRepository = app()->make(EnergyPlanRepository::class);
            $planInfo = $energyPlanRepository->get($meterInfo['plan_id'])->toArray();

            $data = $this->summaryBillSettlement($data, $planInfo);
            if (isset($planInfo) && is_array($planInfo)) {
                $data['plan_record'] = json_encode($planInfo, JSON_UNESCAPED_UNICODE);
            }
            $billId = $data['bill_id'];
            $isSettle = $data['is_settle'];
            $totalAmount = $data['total_amount'];
            unset($data['bill_id']);
            unset($data['is_settle']);
            unset($data['total_amount']);

            $data['start_date'] = $meterInfo['base_date'];
            $data['end_date'] = date("Y-m-d");
            $data['energy_name'] = $meterInfo['energy_name'];
            $data['energy_type'] = $meterInfo['energy_type'];
            $data['month_time'] = date('Y-m');
            $data['room_id'] = $meterInfo['room_id'];
            $data['property_id'] = $propertyId;
            $info = $this->dao->create($data);
            if ($isSettle == 1 && $info['id'] > 0) {
                ## 更新设备读数
                $updateData = [
                    'base_z' => $info['end_num_z'],
                    'base_j' => $info['end_num_j'],
                    'base_f' => $info['end_num_f'],
                    'base_p' => $info['end_num_p'],
                    'base_g' => $info['end_num_g'],
                    'base_date' => date("Y-m-d"),
                ];
                $energyMeterRepository->energyMeterUpdate($data['energy_id'], $updateData);
            }

            /** @var BillCatalogRepository $billCatalogRepository */
            $billCatalogRepository = app()->make(BillCatalogRepository::class);
            $billCatalogData['property_id'] = $propertyId;
            $billCatalogData['energy_bill_id'] = $info['id'];
            $billCatalogData['bill_id'] = $billId;
            $billCatalogData['amount'] = $totalAmount;
            $billCatalogData['start_date'] = $meterInfo['base_date'];
            $billCatalogData['end_date'] = date("Y-m-d");
            $billCatalogData['total_amount'] = $totalAmount;
            $billCatalogRepository->create($billCatalogData);

            /** @var PropertyUsersLogRepository $repository */
            $repository = app()->make(PropertyUsersLogRepository::class);
            $repository->addInfo($propertyId, $userId, 'ENERGY.BILL.ADD', $data);
            return $info;
        });
    }


    public function editInfo($info, array $data, int $userId = 0)
    {
        return Db::transaction(function () use ($data, $info, $userId) {
            $planInfo = $info['plan_record'];
            $data = $this->summaryBillSettlement($data, $planInfo);
            $isSettle = $data['is_settle'] ?? 0;
            unset($data['is_settle']);
            if ($isSettle == 1 && $info['energy_id'] > 0) {
                /** @var EnergyMeterRepository $energyMeterRepository */
                $energyMeterRepository = app()->make(EnergyMeterRepository::class);
                $updateData = [
                    'base_z' => $data['end_num_z'],
                    'base_j' => $data['end_num_j'],
                    'base_f' => $data['end_num_f'],
                    'base_p' => $data['end_num_p'],
                    'base_g' => $data['end_num_g'],
                ];
                $energyMeterRepository->energyMeterUpdate($info['energy_id'], $updateData);
            }
            unset($data['total_amount']);
            /** @var PropertyUsersLogRepository $repository */
            $repository = app()->make(PropertyUsersLogRepository::class);
            $repository->addInfo($info['property_id'], $userId, 'ENERGY.BILL.EDIT', $data);
            return $this->dao->update($info['id'], $data);
        });
    }

    public function getDetail(int $id)
    {
        $data = $this->dao->search([])
            ->where('id', $id)
            ->with([
                'energyMeterInfo' => function ($query) {
                    $query->bind(['energy_no' => 'energy_no']);
                },
                'roomInfo' => function ($query) {
                    $query->bind(['full_room_name']);
                }
            ])
            ->find();
        return $data;
    }

    public function batchDelete(array $ids, int $userId = 0)
    {
        $list = $this->dao->selectWhere([
            ['id', 'in', $ids]
        ]);
        if ($list) {
            foreach ($list as $k => $v) {
                $this->deleteInfo($v, $userId);
            }
            return $list;
        }
        return [];
    }

    public function deleteInfo($info, int $userId = 0)
    {
        /** @var PropertyUsersLogRepository $repository */
        $repository = app()->make(PropertyUsersLogRepository::class);
        $repository->addInfo($info['property_id'], $userId, 'ENERGY.BILL.DEL', $info);
        $this->dao->delete($info['id']);
    }


    public function summaryBillSettlement(array $data, $planInfo, $info = [])
    {
        $beilv = $data['beilv'] ?? 1;
        $data['remark'] = '用量';
        $data['basic_amount'] = $data['service_amount'] = $data['loss_amount'] = 0.00;
        # 单费率
        if ($planInfo['mode_type'] == 1) {
            # 用量
            $data['use_num_z'] = bcmul(bcsub($data['end_num_z'], $data['start_num_z'], 4), $beilv, 4);
            # 基础费用计算
            $data['basic_amount'] = bcmul($planInfo['basic_price'], $data['use_num_z'], 4);

            ##  服务费计算
            if ($planInfo['service_switch'] == 1) {
                $data['service_amount'] = bcmul($planInfo['service_price'], $data['use_num_z'], 4);
            }
            $data['remark'] .= $data['use_num_z'];
        }

        # 多费率
        if ($planInfo['mode_type'] == 2) {
            # 用量
            $data['use_num_j'] = bcmul(bcsub($data['end_num_j'], $data['start_num_j'], 4), $beilv, 4);
            $data['use_num_f'] = bcmul(bcsub($data['end_num_f'], $data['start_num_f'], 4), $beilv, 4);
            $data['use_num_p'] = bcmul(bcsub($data['end_num_p'], $data['start_num_p'], 4), $beilv, 4);
            $data['use_num_g'] = bcmul(bcsub($data['end_num_g'], $data['start_num_g'], 4), $beilv, 4);

            $data['use_num_z'] = bcadd($data['use_num_j'], $data['use_num_f'], 4);
            $data['use_num_z'] = bcadd($data['use_num_z'], $data['use_num_p'], 4);
            $data['use_num_z'] = bcadd($data['use_num_z'], $data['use_num_g'], 4);

            $data['start_num_z'] = bcadd($data['start_num_j'], $data['start_num_f'], 4);
            $data['start_num_z'] = bcadd($data['start_num_z'], $data['start_num_p'], 4);
            $data['start_num_z'] = bcadd($data['start_num_z'], $data['start_num_g'], 4);

            $data['end_num_z'] = bcadd($data['end_num_j'], $data['end_num_f'], 4);
            $data['end_num_z'] = bcadd($data['end_num_z'], $data['end_num_p'], 4);
            $data['end_num_z'] = bcadd($data['end_num_z'], $data['end_num_g'], 4);
            # 基础费用计算
            $data['basic_amount_j'] = bcmul($planInfo['basic_price_j'], $data['use_num_j'], 4);
            $data['basic_amount_f'] = bcmul($planInfo['basic_price_f'], $data['use_num_f'], 4);
            $data['basic_amount_p'] = bcmul($planInfo['basic_price_p'], $data['use_num_p'], 4);
            $data['basic_amount_g'] = bcmul($planInfo['basic_price_g'], $data['use_num_g'], 4);

            $data['basic_amount'] = bcadd($data['basic_amount_j'], $data['basic_amount_f'], 4);
            $data['basic_amount'] = bcadd($data['basic_amount'], $data['basic_amount_p'], 4);
            $data['basic_amount'] = bcadd($data['basic_amount'], $data['basic_amount_g'], 4);

            ##  服务费计算
            if ($planInfo['service_switch'] == 1) {
                $data['service_amount_j'] = bcmul($planInfo['service_price_j'], $data['use_num_j'], 4);
                $data['service_amount_f'] = bcmul($planInfo['service_price_f'], $data['use_num_f'], 4);
                $data['service_amount_p'] = bcmul($planInfo['service_price_p'], $data['use_num_p'], 4);
                $data['service_amount_g'] = bcmul($planInfo['service_price_g'], $data['use_num_g'], 4);

                $data['service_amount'] = bcadd($data['service_amount_j'], $data['service_amount_f'], 4);
                $data['service_amount'] = bcadd($data['service_amount'], $data['service_amount_p'], 4);
                $data['service_amount'] = bcadd($data['service_amount'], $data['service_amount_g'], 4);
            }
            if ($data['use_num_j'] > 0) {
                $data['remark'] .= '(尖:' . $data['use_num_j'] . ' kwh)';
            }
            if ($data['use_num_f'] > 0) {
                $data['remark'] .= '(峰:' . $data['use_num_f'] . ' kwh)';
            }
            if ($data['use_num_p'] > 0) {
                $data['remark'] .= '(平:' . $data['use_num_p'] . ' kwh)';
            }
            if ($data['use_num_g'] > 0) {
                $data['remark'] .= '(谷:' . $data['use_num_g'] . ' kwh)';
            }
        }

        # 阶梯率
        if ($planInfo['mode_type'] == 3) {
            # 用量

            $useNum = bcmul(bcsub($data['end_num_z'], $data['start_num_z'], 4), $beilv, 4);
            $data['use_num_z'] = $useNum;
            $data['remark'] .= '用量: ' . $useNum . '，阶梯计费';
            # 基础费用计算
            $basicAmount = 0;
            $stairPrice = $planInfo['stair_price'];
            foreach ($stairPrice as $k => $v) {
                if (isset($stairPrice[$k + 1])) {
                    $tempNum = $stairPrice[$k + 1]['fee_amount'] - $v['fee_amount'];
                    $tempNum = min($tempNum, $useNum);
                } else {
                    $tempNum = $useNum;
                }
                $basicAmount = bcadd($basicAmount, bcmul($tempNum, $v['fee_price'], 4), 4);
                $useNum -= $tempNum;
            }
            $data['basic_amount'] = $basicAmount;
            #服务费计算
            if ($planInfo['service_switch'] == 1) {
                $data['service_amount'] = bcmul($planInfo['service_price'], $data['use_num_z'], 4);
            }
        }

        ## 损耗费用计算
        if ($planInfo['loss_switch'] == 1) {
            $data['loss_amount'] = bcmul(bcadd($data['basic_amount'], $data['service_amount'], 4), $planInfo['loss_per'] / 100, 4);
        }
        $data['total_amount'] = bcadd($data['loss_amount'], bcadd($data['basic_amount'], $data['service_amount'], 4), 4);
        return $data;
    }


    /**
     *  结算时更新设备读数
     * @param $energyId
     * @param $updateData
     * @param string $remark
     * @return int
     * @throws \think\db\exception\DbException
     *
     * @author Amos
     * 2024-03-12 20:38
     */
    public function energyBillUpdate($billId, $updateData)
    {
        return $this->dao->update($billId, $updateData);
    }

    /**
     * 任务结算 后付费账单
     * @param $contractInfo
     * @param $billId
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     *
     * @author Amos
     * 2024-05-14 10:02
     */
    public function taskContractEnertrFee($contractInfo, $billInfo)
    {
        /** @var RoomBasicRepository $roomBasicRepository */
        $roomBasicRepository = app()->make(RoomBasicRepository::class);
        $roomList = $roomBasicRepository->getSearch([])
            ->where('contract_id', $contractInfo['id'])
            ->field('id,property_id')
            ->select();
        if ($roomList) {
            /** @var EnergyMeterRepository $energyMeterRepository */
            $energyMeterRepository = app()->make(EnergyMeterRepository::class);

            /** @var EnergyPlanRepository $energyPlanRepository */
            $energyPlanRepository = app()->make(EnergyPlanRepository::class);

            /** @var BillCatalogRepository $billCatalogRepository */
            $billCatalogRepository = app()->make(BillCatalogRepository::class);

            /** @var BillCateRepository $billCateRepository */
            $billCateRepository = app()->make(BillCateRepository::class);
            foreach ($roomList as $k => $v) {
                $meterList = $energyMeterRepository->getSearch([])
                    ->where('is_bind', 1)
                    ->where('is_public', 2)
                    ->where('plan_type', 1)
                    ->where('room_id', $v['id'])
                    ->where('property_id', $v['property_id'])
                    ->field('id,property_id,property_id,energy_name,energy_type,plan_id,beilv,read_z,read_j,read_f,read_p,read_g,base_z,base_j,base_f,base_p,base_g,base_date')
                    ->select();
                foreach ($meterList as $ka => $va) {
                    $planInfo = $energyPlanRepository->get($va['plan_id'])->toArray();
                    if ($planInfo) {
                        $energyBillData = [
                            'start_num_z' => $va['base_z'],
                            'start_num_j' => $va['base_j'],
                            'start_num_f' => $va['base_f'],
                            'start_num_p' => $va['base_p'],
                            'start_num_g' => $va['base_g'],
                            'end_num_z' => $va['read_z'],
                            'end_num_j' => $va['read_j'],
                            'end_num_f' => $va['read_f'],
                            'use_num_p' => $va['read_p'],
                            'use_num_g' => $va['read_g'],
                        ];
                        $data = $this->summaryBillSettlement($energyBillData, $planInfo);
                        $totalAmount = $data['total_amount'];
                        unset($data['total_amount']);

                        $data['plan_type'] = 1; ## 后付费账单
                        $data['energy_id'] = $va['id'];
                        $data['room_id'] = $va['room_id'];
                        $data['property_id'] = $va['property_id'];
                        $data['start_date'] = $va['base_date'];
                        $data['end_date'] = date("Y-m-d");
                        $data['month_time'] = date('Y-m');
                        $data['property_id'] = $va['property_id'];
                        $data['energy_name'] = $va['energy_name'];
                        $data['energy_type'] = $va['energy_type'];
                        $data['plan_record'] = json_encode($planInfo, JSON_UNESCAPED_UNICODE);
                        $energyBillInfo = $this->dao->create($data);
                        if ($energyBillInfo['id'] > 0) {
                            ## 更新设备读数
                            $updateData = [
                                'base_z' => $va['end_num_z'],
                                'base_j' => $va['end_num_j'],
                                'base_f' => $va['end_num_f'],
                                'base_p' => $va['end_num_p'],
                                'base_g' => $va['end_num_g'],
                                'base_date' => date("Y-m-d"),
                            ];
                            $energyMeterRepository->energyMeterUpdate($va['id'], $updateData);
                        }
                        $billCatalogData['bill_id'] = $billInfo['id'];
                        $billCatalogData['amount'] = $totalAmount;
                        $billCatalogData['total_amount'] = $totalAmount;
                        $billCatalogData['start_date'] = $va['base_date'];
                        $billCatalogData['end_date'] = date("Y-m-d");
                        $billCatalogData['status'] = $billInfo['status']; ## 审核状态
                        $billCatalogData['energy_bill_id'] = $energyBillInfo['id']; ## 能源账单 ID
                        $billCatalogData['month_time'] = $billInfo['month_time'];
                        $billCatalogData['contract_id'] = $billInfo['contract_id'];
                        $billCatalogData['property_id'] = $billInfo['property_id'];
                        $billCatalogData['cate_id'] = $billCateRepository->getBillCateId(['is_class' => 2, 'set_finance' => $va['energy_type']]);
                        $billCatalogRepository->create($billCatalogData);
                    }
                }
            }
        }
    }

    /**
     * 任务结算 后付费 均摊费
     * @param $contractInfo
     * @param $billId
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     *
     * @author Amos
     * 2024-05-14 10:02
     */
    public function taskSharedExpenses($contractInfo, $billInfo)
    {
        /** @var RoomBasicRepository $roomBasicRepository */
        $roomBasicRepository = app()->make(RoomBasicRepository::class);
        $roomList = $roomBasicRepository->getSearch([])
            ->where('contract_id', $contractInfo['id'])
            ->field('id,property_id')
            ->select();
        if ($roomList) {
            /** @var EnergySharedRoomRepository $energySharedRoomRepository */
            $energySharedRoomRepository = app()->make(EnergySharedRoomRepository::class);

            /** @var BillCatalogRepository $billCatalogRepository */
            $billCatalogRepository = app()->make(BillCatalogRepository::class);

            /** @var EnergyMeterRepository $energyMeterRepository */
            $energyMeterRepository = app()->make(EnergyMeterRepository::class);

            /** @var EnergyPlanRepository $energyPlanRepository */
            $energyPlanRepository = app()->make(EnergyPlanRepository::class);

            /** @var BillCateRepository $billCateRepository */
            $billCateRepository = app()->make(BillCateRepository::class);

            foreach ($roomList as $k => $v) {
                $sharedRoomList = $energySharedRoomRepository->getSearch([])
                    ->where('is_settle', 1)
                    ->where('room_id', $v['id'])
                    ->where('property_id', $v['property_id'])
                    ->select();
                foreach ($sharedRoomList as $ka => $va) {
                    $meterInfo = $energyMeterRepository->getSearch([])
                        ->where('id', $va['energy_id'])
                        ->field('id,plan_id,energy_name,energy_type')
                        ->find();
                    if ($meterInfo) {
                        $energyBillData = [
                            'start_num_z' => 0.00,
                            'start_num_j' => 0.00,
                            'start_num_f' => 0.00,
                            'start_num_p' => 0.00,
                            'start_num_g' => 0.00,
                            'end_num_z' => $va['use_num_z'],
                            'end_num_j' => $va['use_num_j'],
                            'end_num_f' => $va['use_num_f'],
                            'use_num_p' => $va['use_num_p'],
                            'use_num_g' => $va['use_num_g'],
                        ];
                        $planInfo = $energyPlanRepository->get($meterInfo['plan_id'])->toArray();
                        $data = $this->summaryBillSettlement($energyBillData, $planInfo);
                        $totalAmount = $data['total_amount'];
                        unset($data['total_amount']);

                        $data['plan_type'] = 1; ## 后付费账单
                        $data['room_id'] = $va['room_id'];
                        $data['energy_id'] = $va['energy_id']; ## 公摊设备 ID
                        $data['start_date'] = $va['start_date'];
                        $data['end_date'] = date("Y-m-d");
                        $data['property_id'] = $va['property_id'];
                        $data['energy_name'] = $meterInfo['energy_name'];
                        $data['energy_type'] = $meterInfo['energy_type'];
                        $data['month_time'] = $billInfo['month_time'];
                        $data['contract_id'] = $billInfo['contract_id'];
                        $data['plan_record'] = json_encode($planInfo, JSON_UNESCAPED_UNICODE);
                        $energyBillInfo = $this->dao->create($data);
                        if ($energyBillInfo['id'] > 0) {
                            ## 更新己经结算的公摊量
                            $energySharedRoomRepository->update($va['id'], ['is_settle' => 9, 'end_date' => date("Y-m-d")]);
                            ## 新增公摊数据
                            $energySharedRoomRepository->create([
                                'property_id' => $va['property_id'],
                                'energy_id' => $va['energy_id'],
                                'plan_id' => $va['plan_id'],
                                'room_id' => $va['room_id'],
                                'scale' => $va['scale'],
                                'start_date' => date("Y-m-d"),
                                'is_settle' => 1,
                            ]);
                        }
                        $billCatalogData['is_shared'] = 1; ## 公摊费用标注
                        $billCatalogData['bill_id'] = $billInfo['id'];
                        $billCatalogData['amount'] = $totalAmount;
                        $billCatalogData['total_amount'] = $totalAmount;
                        $billCatalogData['start_date'] = $va['start_date'];
                        $billCatalogData['end_date'] = date("Y-m-d");
                        $billCatalogData['energy_bill_id'] = $energyBillInfo['id'];
                        $billCatalogData['status'] = $billInfo['status']; ## 审核状态
                        $billCatalogData['month_time'] = $billInfo['month_time'];
                        $billCatalogData['contract_id'] = $billInfo['contract_id'];
                        $billCatalogData['property_id'] = $billInfo['property_id'];
                        $billCatalogData['cate_id'] = $billCateRepository->getBillCateId(['is_class' => 2, 'set_finance' => $meterInfo['energy_type']]);
                        $billCatalogRepository->create($billCatalogData);
                    }
                }
            }
        }
    }
}